#ifndef GRAPH_H
#define GRAPH_H

#include <cassert>
//#include <stdexcept>

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include "Vertex.h"
#include "Edge.h"
using namespace std;


class Edge;
class Vertex;

class Graph{

private:
	vector<Vertex*> vertList;
	vector<Edge*> edgeList;


public:
	Graph(string filename) {
		// This function is the most difficult one. Be carefull.
		// Using ifstream, e.g. ifstream ifs(filename.c_str()); 
		// make new vertices and edges, also fill out the information for them
		// the expected result will be: vertList contains all vertices and edgeList contains all edges. 
		// and the vertices and edges should contains information, e.g. weight, source/end vertex pointer for edge
		
		ifstream ifs(filename.c_str());
		if (!ifs)
		{
			cerr << "File could not be read!";
		}
		else
		{
			int v_no;
			ifs >> v_no;
			for (int i = 0; i < v_no; i++)
			{
				Vertex* v;
				v = new Vertex(i+1);
				//vertList.push_back(new Vertex(i+1));
				vertList.push_back(v);
			}

			int sid, eid;
			double weight = 0.0;
			sid = eid = 0;

			ifs >> sid;
			while( sid != -1){
				ifs >> eid;
				while (eid != -1)
				{
					ifs >> weight;
					Edge* e;
					e = new Edge(vertList[sid-1], vertList[eid-1], weight);
					edgeList.push_back(e);
					//edgeList.push_back(new Edge(vertList[sid-1], vertList[eid-1], weight));
					vertList[sid-1]->enOutList(*e);
					vertList[eid-1]->enInList(*e);
					//vertList[sid-1]->enOutList(*edgeList[edgeList.size()-1]);
					//vertList[eid-1]->enInList(*edgeList[edgeList.size()-1]);
					ifs >> eid;
				}
				ifs >> sid;
			}
		}
	}

	void PrintGraph() // print out all the edges and associated vertices in the entire graph
	{
		cout<<"Graph is as follows: "<<endl;

        // print all edges and related vertices
		for(int i=0;i<edgeList.size();i++)
		{
			// print out weight of edge
            // and source/end vertex id
			cout << '(' << edgeList[i]->getsVertP()->getID() << "->"
				<< edgeList[i]->geteVertP()->getID() << ") "
				<< "wt: " << edgeList[i]->getWeight() << '\n';
		}

        // print all vertices and related edges
		for(int i=0;i<vertList.size();i++)
		{
			// print out in edges and out edges with weight information
			vertList[i]->printInEdge();
			vertList[i]->printOutEdge();
		}
	}
	
	const vector<Vertex*>& get_vertices() const
	{
		return vertList;
	}
};
#endif
